package multimedia.model.quantize;

import java.util.Vector;

import magick.ColorspaceType;
import multimedia.model.ModifiedImage;
import multimedia.model.colorspace.ColorspaceInterface;
import multimedia.util.ProjectConstants;

public class Quantizer
{
    public static int UNIFORM = 1;
    public static int VARIABLE = 2;
    
    private ModifiedImage image = null;
    private float[] minRanges;
    private float[] maxRanges;

    public Quantizer( ModifiedImage image , int colorspace )
    {
        this.image = image;
        
        // Set min and max values depending on colorspace 
        if( colorspace == ColorspaceType.YIQColorspace )
        {
            minRanges = ProjectConstants.YIQ_MIN_RANGES;
            maxRanges = ProjectConstants.YIQ_MAX_RANGES;
        }
        else
        {
            minRanges = ProjectConstants.RGB_MIN_RANGES;
            maxRanges = ProjectConstants.RGB_MAX_RANGES;
        }
    }

    public void uniformQuantization(  int n1, int n2, int n3 )
    {
        float[] N = new float[]{n1,n2,n3};
        
        // Create a bin for each color instance.
        float[] binSizes = new float[3];
        
        
        // Calculate the bin size based on the ranges
        for( int i = 0; i < binSizes.length; i++ )
        {
            binSizes[i] = (Math.abs(minRanges[i]) + Math.abs(maxRanges[i]))/N[i];
        }
        
        // Create an alias to a ColorspaceInterface vector
        Vector<ColorspaceInterface> pixelVector = image.getImagePixelHolder().getRgbVector();
        
        for ( ColorspaceInterface pixel : pixelVector )
        {
            float[] x = new float[]{pixel.getFirstComponent(),pixel.getSecondComponent(), pixel.getThirdComponent()};
            float[] q = new float[3];
            
            for( int i = 0; i < x.length; i++ )
            {
                q[i] = binSizes[i]*((float)Math.floor( ( x[i] + Math.abs(minRanges[i]) )/binSizes[i] ) ) - Math.abs(minRanges[i]); 
            }
            
            pixel.setFirstComponent( q[0] );
            pixel.setSecondComponent( q[1] );
            pixel.setThirdComponent( q[2] );
        }
    }
    
    public void variableQuantization( int n1, int n2, int n3, float alpha )
    {
        float[][] N = new float[3][];
        N[0] = new float[n1];
        N[1] = new float[n2];
        N[2] = new float[n3];
        
        // Populate N
//        for( int i = 0; i < N.length; i++ )
//        {
//            for( int j = 0; j < N[i].length; j++ )
//                N[i][j] = j;
//        }
        
        float[][] unscaledRange = new float[3][];
        unscaledRange[0] = new float[n1];
        unscaledRange[1] = new float[n2];
        unscaledRange[2] = new float[n3];
        
        // Calculate unscaledRange
        for( int i = 0; i < unscaledRange.length; i++ )
        {
            for( int j = 0; j < unscaledRange[i].length; j++ )
            {
                // Populate N
                N[i][j] = j;
                
                // Calculate unscaledRange
                unscaledRange[i][j] = (float) Math.pow(N[i][j],alpha);
            }
        }
        
        float[][] scaledRange = new float[3][];
        scaledRange[0] = new float[n1];
        scaledRange[1] = new float[n2];
        scaledRange[2] = new float[n3];
        
        // Calculate scaledRange
        for( int i = 0; i < scaledRange.length; i++ )
        {
            for( int j = 0; j < scaledRange[i].length; j++ )
            {
                scaledRange[i][j] = (unscaledRange[i][j]/unscaledRange[i][N[i].length - 1]) * 
                                    (Math.abs(minRanges[i]) + Math.abs(maxRanges[i]) ) - 
                                    Math.abs(minRanges[i]);
            }
        }
        
        // Create an alias to a ColorspaceInterface vector
        Vector<ColorspaceInterface> pixelVector = image.getImagePixelHolder().getRgbVector();
        
        // Calculate the value in between the bin
        for ( ColorspaceInterface pixel : pixelVector )
        {
            float[] x = new float[]{pixel.getFirstComponent(),pixel.getSecondComponent(), pixel.getThirdComponent()};
            float[] q = new float[3];
            
            for( int i = 0; i < x.length; i++ )
            {
                for( int j = 0; j < scaledRange[i].length - 1; j++)
                {
                    if( scaledRange[i][j] < x[i] && x[i] < scaledRange[i][j+1] )
                    {
                        // Select the midpoint
                        q[i] = ( scaledRange[i][j] + scaledRange[i][j+1] )/2;
                        break;
                    }
                }
            }
            
            // Save the new pixels
            pixel.setFirstComponent( q[0] );
            pixel.setSecondComponent( q[1] );
            pixel.setThirdComponent( q[2] );
        }
    }

    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
}
